/**

This file is part of MaCI/GIMnet.

MaCI/GIMnet is free software: you can redistribute it and/or modify it 
under the terms of the GNU Lesser General Public License as published 
by the Free Software Foundation, either version 3 of the License, or 
(at your option) any later version.

MaCI/GIMnet is distributed in the hope that it will be useful, but WITHOUT 
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 
FITNESS FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public 
License for more details.

You should have received a copy of the GNU Lesser General Public 
License along with GIMnet. (See COPYING.LESSER) If not, see 
<http://www.gnu.org/licenses/>.

**/
#include "CWindowsSerialDriver.h"

CWindowsSerialDriver::CWindowsSerialDriver(){
  portHandle = NULL;
}
CWindowsSerialDriver::~CWindowsSerialDriver(){};
/**
* Open the serial driver
* Opens the handle and sets the communication parameters
* @p serialport : The serial port number = /dev/ttyS+(serialport)
* @p baudrate : the communication flow rate (speed).
* @p charsize : the character size (7,8 bits)
* @p parity   : 0=none, 1=odd, 2=even
* @p stopbits : the number of stop bits (1 or 2)
*
* @return true in success, false if failure
*/
bool CWindowsSerialDriver::Open(const char *serialport, int baudrate,int dataBits,int parity, int stopBits){
	//char serial_name[50];
	
	if(portHandle > 0){
		fprintf(stderr,"CLinuxSerialDriver::Open(): Already opened! Close the port first!\n");
		return false;
	}
	//sprintf(serial_name,"COM%d",serial_port);
	
	if(!openSerialPortHandle(serialport)){
		fprintf(stderr,"CLinuxSerialDriver::Open(): Failed to Open port %s  \n",serial_name);
		return false;
	}
	
	if(setCommParameters(baudrate,dataBits,parity, stopBits )!=0){
		fprintf(stderr,"CLinuxSerialDriver::Open(): Failed to set port parameters for %s\n",serial_name);
		return false;
	}
	return true;
}
bool CWindowsSerialDriver::Close(){
	CloseHandle(portHandle);
	return true;
}

/**
 * Clears the serial buffer
 * @return true on success, else false
 */
bool CWindowsSerialDriver::Clear(){
	fprintf(stderr,"CWindowsSerialDriver::Clear():: MUST BE IMPLEMENTED!!\n");
	return false;
}


/**
	* Read the data from the serial. 
	* The port is selected and then buffer read one character a time until the length is reached or 
	* the buffer is emptied and the number of retries is exceeded
	* 
	* @p *inbuf buffer that stores the input characthers (user must initialize)
	* @p length the # of bytes of wanted to receive
	*
	* @return     -1 on timeout, else the number of bytes read. 
	*/
int CWindowsSerialDriver::Read(char *inbuf, int length){
	DWORD bytesRead;
	BOOL status;
	int returnVal;

	/* receive response data from the serial port if expected. */
	returnVal = 0;
	if (responseLength>0) {
		status = ReadFile(portHandle, inbuf, length, &bytesRead, NULL);
		if (status) {
			/* check for wrong number of bytes returned. */
			if ((int)bytesRead != responseLength)
				returnVal = bytesRead ;

		} else
			returnVal = bytesRead ;
	}
	return returnVal;
}
/**
	* Writes data to serial
	*
	* @p data      data to be written
	* @p length    the length of the data
	* @return      true in success, else false
	*/
bool CWindowsSerialDriver::Write(char* data, int length){
	DWORD bytesWritten;
	BOOL status;
	/* write the command. */
	status = WriteFile (portHandle, data, length, &bytesWritten, 0);
	if (!status)
		return false;  //!! check bytes written?
	else
		return true;
}

/////////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////// PRIVATES /////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////////////////////////		
/**
	* Opens serial port 
	* @p port The serial port folder "/dev/ttyS0" 
	* @return true if success, else false
	*/
bool CWindowsSerialDriver::openSerialPortHandle(const char *portname){
	portHandle = CreateFile(portname, 
													GENERIC_READ | GENERIC_WRITE,
													0, // exclusive access
													NULL, // no security
													OPEN_EXISTING,
													0, // no overlapped I/O
													NULL); // null template
	
	if (portHandle == INVALID_HANDLE_VALUE) {
		return false;
	} else {
		SetupComm(portHandle, 128, 128);	// set buffer sizes	
		return true;
	}
}

/**
	* setCommParameters
	* @p baudrate : the communication flow rate (speed).
	* @p charsize : the character size (7,8 bits)
	* @p parity   : 0=none, 1=odd, 2=even
	* @p stopbits : the number of stop bits (1 or 2)
	*
	* @return      0 if the settings succeeded.
	*              -1 if there was an error.
	*/
int CWindowsSerialDriver::setCommParameters(int baudrate,int dataBits,int parity, int stopBits ){
	BOOL ready;
	DCB  dcb;

	ready = GetCommState(portHandle, &dcb);
	if (!ready) {
		return return -1;
	}
	if (stopbits==1) {
		stopbits=0;    /* in Windows 0 means 1 stopbit */
	}
	dcb.BaudRate = baudrate;
	dcb.ByteSize = charsize;
	dcb.Parity = parity;
	dcb.StopBits = stopbits;
	dcb.fAbortOnError = TRUE;
	ready = SetCommState(portHandle, &dcb);
	if (!ready)
		return -1;
	else
		return 0;
}